package belf.migrate.engine.ddl.trigger.mysql;

import belf.migrate.api.model.QualifiersModel;
import belf.migrate.api.table.schema.Catalog;
import belf.migrate.api.util.QuoteType;
import belf.migrate.engine.ddl.BaseDDLConvert;
import belf.migrate.engine.ddl.helper.mysql.MySqlAntlrBuilder;
import belf.migrate.plugin.mysql.antlr.MySqlLexer;
import belf.migrate.plugin.mysql.antlr.MySqlParser;
import belf.migrate.plugin.mysql.antlr.MySqlParserBaseListener;
import belf.migrate.plugin.mysql.antlr.MySqlParserBaseVisitor;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.apache.commons.lang3.StringUtils;

public class MySql2KingbaseTriggerConvert extends BaseDDLConvert {

    /**
     * 带上schema参数的构造方法，表示所有标识符都要加上前缀schema
     * @param objectName
     * @param sql
     * @param sourceCatalog
     * @param sinkCatalog
     * @param schema
     */
    public MySql2KingbaseTriggerConvert(String objectName, String sql, Catalog sourceCatalog, Catalog sinkCatalog,
                                        String schema, QualifiersModel qualifiersModel) {
        super(objectName, sql, sourceCatalog, sinkCatalog, schema, qualifiersModel);
        String taskType = sourceCatalog + "-" + sinkCatalog;
    }

    @Override
    public String convert() {
        CharStream input = CharStreams.fromString(sql);

        // 创建词法分析器和解析器
        MySqlLexer lexer = new MySqlLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        MySqlParser parser = new MySqlParser(tokens);

        // 从解析器中获取起始规则并进行解析
        MySqlParser.RootContext tree = parser.root();
        MySqlTriggerVisitor triggerVisitor = new MySqlTriggerVisitor(this);
        triggerVisitor.visit(tree);
        return triggerVisitor.toTriggerDDL();
    }

    private class MySqlTriggerVisitor extends MySqlParserBaseVisitor<String> {
        private BaseDDLConvert ddlConvert;

        private String triggerName;
        private String tableName;

        private MySqlParser.CreateTriggerContext createTriggerContext;
        //mysql的触发器定义没有包含BEGIN...END的，以这个为根节点进行遍历
        private MySqlParser.RoutineBodyContext routineBodyContext;

        public MySqlTriggerVisitor(BaseDDLConvert ddlConvert) {
            this.ddlConvert = ddlConvert;
        }

        @Override
        public String visitCreateTrigger(MySqlParser.CreateTriggerContext ctx) {
            this.createTriggerContext = ctx;
            triggerName = createTriggerContext.fullId().get(0).getText().trim();
            triggerName = StringUtils.replace(triggerName, "`", QuoteType.DOUBLE_QUOTE.getValue());
            tableName = createTriggerContext.tableName().fullId().getText().trim();
            tableName = StringUtils.replace(tableName, "`", QuoteType.DOUBLE_QUOTE.getValue());
            return visitChildren(ctx);
        }

        @Override
        public String visitRoutineBody(MySqlParser.RoutineBodyContext ctx) {
            this.routineBodyContext = ctx;
            return visitChildren(ctx);
        }

        public String toTriggerDDL() {
            StringBuilder sb = new StringBuilder();
            int childCount = createTriggerContext.getChildCount();
            for (int i = 0; i < childCount; i++) {
                ParseTree parseTree = createTriggerContext.getChild(i);
                if (parseTree instanceof TerminalNode) {
                    TerminalNode terminalNode = (TerminalNode)parseTree;
                    sb.append(terminalNode.getText() + " ");
                } else if (parseTree instanceof MySqlParser.FullIdContext){
                    sb.append(triggerName + " ");
                } else if (parseTree instanceof MySqlParser.TableNameContext) {
                    if (schema != null && !(tableName.toUpperCase().contains(schema.toUpperCase()))) {
                        sb.append(qualifiersModel.getLeftQuote() + schema + qualifiersModel.getRightQuote() + ".");
                    }
                    sb.append(tableName + " ");
                }
            }

            //这里定义一个空的StringBuilder，接收BEGIN...END之间的语句
            StringBuilder internalSb = new StringBuilder();
            MySqlAntlrBuilder builder = new MySqlAntlrBuilder(ddlConvert, internalSb, QuoteType.DOUBLE_QUOTE.getValue(), schema);
            MySqlTriggerListener listener = new MySqlTriggerListener(builder);
            ParseTreeWalker walker = new ParseTreeWalker();
            if (routineBodyContext != null) {
                walker.walk(listener, routineBodyContext);
            }

            String sqlBody = listener.getBody().trim();
            if (!sqlBody.endsWith(";")) {//对于没有BEGIN...END的触发器body子句，可能没有分号结尾，需强制加上分号
                sqlBody += ";";
            }
            if (!(sqlBody.toUpperCase().startsWith("BEGIN"))) {//对于没有BEGIN...END的触发器body子句，需强制加上BEGIN
                sb.append("\nBEGIN\n");
            }

            sb.append(sqlBody);
            if (!sqlBody.endsWith(";")) {
                sb.append(";");
            }

            if (!(sqlBody.toUpperCase().endsWith("END;"))) {//对于没有BEGIN...END的触发器body子句，需强制加上END
                sb.append("\nEND;");
            }

            return sb.toString();
//            return SqlFormatter.of(Dialect.PlSql).format(sb.toString()); //达梦数据库的语法兼容Oracle
        }
    }

    private class MySqlTriggerListener extends MySqlParserBaseListener {
        private MySqlAntlrBuilder builder;

        public MySqlTriggerListener(MySqlAntlrBuilder builder) {
            this.builder = builder;
        }

        @Override
        public void visitTerminal(TerminalNode node) {
            String text = node.getText().trim();
            if ("SET".equalsIgnoreCase(text) &&
                    node.getParent() instanceof MySqlParser.SetStatementContext) {
                //忽略关键词“SET”
            } else if ("NEW".equalsIgnoreCase(text)) {
                builder.append("NEW");
            } else if ("OLD".equalsIgnoreCase(text)) {
                builder.append("OLD");
            } else if (hasAncestor("FullIdContext", node) && text.startsWith(".")) {
                builder.append(text);
            } else {
                builder.output(node);
            }

        }

        public String getBody() {
            return builder.toSql();
        }
    }
}
